package com.wsyu.springbootbackend.core.util;

import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import net.minidev.json.JSONObject;

import java.util.Map;
import java.util.Objects;

@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE) // 私有构造，禁止外部实例化
public class JwtUtils {

    /**
     * JWT 工具类（链式构建+通用解析）
     * 支持自定义荷载、过期时间、签名密钥，基于建造者模式实现流畅调用
     */

    // ==================== 常量配置（可迁移到配置文件）====================
    // 默认签名密钥（建议生产环境从配置中心/环境变量读取）
    private static final String DEFAULT_SECRET = "hello world goodbye thank you very much see you next time";
    // 默认过期时间：2小时（单位：毫秒）
    // private static final long DEFAULT_EXPIRE_MS = 2 * 60 * 60 * 1000;
    // 常用荷载键（避免硬编码）
    public static final String KEY_USERNAME = "username";
    public static final String KEY_AUTHORITIES = "authorities";
    // public static final String KEY_EXPIRE = "exp"; // JWT标准过期键（会自动映射到JWS头）


    static {
        log.info("JWT 默认签名密钥初始化（生产环境请替换为配置化密钥）：{}", DEFAULT_SECRET);
    }


    // ==================== 链式构建器核心 ====================

    /**
     * JWT 建造者（内部类，负责配置和生成JWT）
     */
    public static class JwtBuilder {
        // 必选参数（默认值兜底）
        private String secret = DEFAULT_SECRET;
        private JWSAlgorithm algorithm = JWSAlgorithm.HS256; // 默认HS256对称加密
        // 可选参数
        private final JSONObject payload = new JSONObject(); // JWT荷载
        private Long expireMs; // 过期时间（毫秒）


        /**
         * 私有构造，通过 JwtUtils.create() 获取实例
         */
        private JwtBuilder() {
        }


        /**
         * 配置签名密钥（默认使用DEFAULT_SECRET）
         */
        public JwtBuilder secret(String secret) {
            if (Objects.nonNull(secret) && !secret.trim().isEmpty()) {
                this.secret = secret;
            }
            return this;
        }


        /**
         * 配置签名算法（默认HS256，支持HS384/HS512等对称算法）
         */
        public JwtBuilder algorithm(JWSAlgorithm algorithm) {
            if (Objects.nonNull(algorithm)) { // 仅支持HMAC系列对称算法（可扩展）
                this.algorithm = algorithm;
            }
            return this;
        }


        /**
         * 添加单个荷载（键值对）
         */
        public JwtBuilder addPayload(String key, Object value) {
            if (Objects.nonNull(key) && !key.trim().isEmpty() && Objects.nonNull(value)) {
                this.payload.put(key, value);
            }
            return this;
        }

        public JwtBuilder addUsername(String value) {
            if (Objects.nonNull(value) && !value.trim().isEmpty()) {
                this.payload.put(KEY_USERNAME, value);
            }
            return this;
        }

        public JwtBuilder addAuthorities(String value) {
            if (Objects.nonNull(value) && !value.trim().isEmpty()) {
                this.payload.put(KEY_AUTHORITIES, value);
            }
            return this;
        }


        /**
         * 批量添加荷载（Map）
         */
        public JwtBuilder addAllPayload(Map<String, Object> payloadMap) {
            if (Objects.nonNull(payloadMap) && !payloadMap.isEmpty()) {
                this.payload.putAll(payloadMap);
            }
            return this;
        }


        /**
         * 配置过期时间（毫秒）
         */
        public JwtBuilder expireMs(long expireMs) {
            if (expireMs > 0) {
                this.expireMs = expireMs;
            }
            return this;
        }


        /**
         * 配置过期时间（秒，兼容JWT标准时间单位）
         */
        public JwtBuilder expireSec(long expireSec) {
            if (expireSec > 0) {
                this.expireMs = expireSec * 1000;
            }
            return this;
        }


        /**
         * 构建并生成JWT字符串
         *
         * @throws RuntimeException/JOSEException 签名过程异常
         */
        @SneakyThrows
        public String build() {
            // 1. 处理过期时间（默认2小时）
            // long actualExpireMs = Objects.isNull(this.expireMs) ? DEFAULT_EXPIRE_MS : this.expireMs;
            // Date expireDate = new Date(System.currentTimeMillis() + actualExpireMs);
            // this.payload.put(KEY_EXPIRE, expireDate.getTime() / 1000); // JWT标准：exp用秒级时间戳


            // 2. 构建JWS头（算法+类型）
            JWSHeader header = new JWSHeader.Builder(algorithm)
                    .type(JOSEObjectType.JWT) // 明确JWT类型
                    .build();

            // 3. 签名生成JWT
            JWSSigner signer = new MACSigner(secret); // 基于密钥创建签名器
            JWSObject jwsObject = new JWSObject(header, new Payload(payload));
            jwsObject.sign(signer); // 执行签名

            // log.debug("JWT生成成功，荷载内容：{}，过期时间：{}", payload, expireDate);
            log.debug("JWT生成成功，荷载内容：{}", payload);
            return jwsObject.serialize();
        }
    }


    // ==================== 对外入口方法 ====================

    /**
     * 获取JWT建造者实例（链式调用入口）
     */
    public static JwtBuilder create() {
        return new JwtBuilder();
    }


    // ==================== 原有解析/校验功能（优化重构） ====================

    /**
     * 校验JWT有效性（签名+过期时间）
     */
    public static boolean verify(String jwtString) {
        return verify(jwtString, DEFAULT_SECRET);
    }


    /**
     * 自定义密钥校验JWT有效性
     */
    @SneakyThrows
    public static boolean verify(String jwtString, String secret) {
        if (Objects.isNull(jwtString) || jwtString.trim().isEmpty()) {
            log.warn("JWT字符串为空，校验失败");
            return false;
        }

        try {
            // 1. 解析JWT
            JWSObject jwsObject = JWSObject.parse(jwtString);
            // 2. 校验签名
            JWSVerifier verifier = new MACVerifier(secret);
            if (!jwsObject.verify(verifier)) {
                log.warn("JWT签名校验失败");
                return false;
            }
/*
            // 3. 校验过期时间
            JSONObject payload = new JSONObject(jwsObject.getPayload().toJSONObject());
            long expSec = payload.getAsNumber(KEY_EXPIRE).longValue();
            long currentSec = System.currentTimeMillis() / 1000;
            if (currentSec > expSec) {
                log.warn("JWT已过期，当前时间：{}，过期时间：{}", currentSec, expSec);
                return false;
            }
*/

            log.debug("JWT校验成功");
            return true;
        } catch (Exception e) {
            log.error("JWT校验异常：{}", e.getMessage(), e);
            return false;
        }
    }


    /**
     * 从JWT中获取指定键的荷载值
     */
    @SneakyThrows
    public static <T> T getPayloadValue(String jwtString, String key, Class<T> valueType) {
        if (!verify(jwtString)) { // 先校验有效性
            throw new JOSEException("JWT无效，无法解析荷载");
        }

        JWSObject jwsObject = JWSObject.parse(jwtString);
        Map<String, Object> payload = jwsObject.getPayload().toJSONObject();
        Object value = payload.get(key);

        if (Objects.isNull(value)) {
            log.warn("JWT中未找到键：{}", key);
            return null;
        }

        try {
            return valueType.cast(value); // 类型转换（确保安全）
        } catch (ClassCastException e) {
            throw new JOSEException("JWT荷载值类型不匹配，键：" + key + "，期望类型：" + valueType.getName());
        }
    }


    /**
     * 快捷获取用户名（兼容原有功能）
     */
    public static String getUsername(String jwtString) {
        return getPayloadValue(jwtString, KEY_USERNAME, String.class);
    }

    /**
     * 快捷获取权限（修复原有方法名重复问题）
     */
    public static String getAuthorities(String jwtString) {
        return getPayloadValue(jwtString, KEY_AUTHORITIES, String.class);
    }


    /**
     * 获取完整荷载（返回Map，支持灵活解析）
     */
    @SneakyThrows
    public static Map<String, Object> getFullPayload(String jwtString) {
        if (!verify(jwtString)) {
            throw new JOSEException("JWT无效，无法获取完整荷载");
        }
        JWSObject jwsObject = JWSObject.parse(jwtString);
        return jwsObject.getPayload().toJSONObject();
    }

}